package zzzhc.image.recognize.filter;

import zzzhc.image.recognize.Filter;
import zzzhc.image.recognize.RecognizeContext;

public class BinaryFilter implements Filter {

	private static final long serialVersionUID = 7793066374463358393L;

	private int threshold = -1;

	public int getThreshold() {
		return threshold;
	}

	public void setThreshold(int threshold) {
		this.threshold = threshold;
	}

	private int[] getHistogram(RecognizeContext context) {
		context.grayProcess();
		int[] histogram = new int[256];
		for (int y = 0; y < context.getHeight(); y++) {
			for (int x = 0; x < context.getWidth(); x++) {
				histogram[context.getValue(x, y)]++;
			}
		}
		return histogram;
	}

	private int getAutoThreshold(int[] histogram) {
		int level;
		int maxValue = histogram.length - 1;
		double result, sum1, sum2, sum3, sum4;

		int count0 = histogram[0];
		histogram[0] = 0; // set to zero so erased areas aren't included
		int countMax = histogram[maxValue];
		histogram[maxValue] = 0;
		int min = 0;
		while ((histogram[min] == 0) && (min < maxValue))
			min++;
		int max = maxValue;
		while ((histogram[max] == 0) && (max > 0))
			max--;
		if (min >= max) {
			histogram[0] = count0;
			histogram[maxValue] = countMax;
			level = histogram.length / 2;
			return level;
		}

		int movingIndex = min;
		do {
			sum1 = sum2 = sum3 = sum4 = 0.0;
			for (int i = min; i <= movingIndex; i++) {
				sum1 += i * histogram[i];
				sum2 += histogram[i];
			}
			for (int i = (movingIndex + 1); i <= max; i++) {
				sum3 += i * histogram[i];
				sum4 += histogram[i];
			}
			result = (sum1 / sum2 + sum3 / sum4) / 2.0;
			movingIndex++;
		} while ((movingIndex + 1) <= result && movingIndex < max - 1);

		histogram[0] = count0;
		histogram[maxValue] = countMax;
		level = (int) Math.round(result);
		return level;
	}

	public void doFilter(RecognizeContext context) {
		int[] histogram = getHistogram(context);

		int divThreshold = getThreshold();
		if (divThreshold < 0) {
			divThreshold = getAutoThreshold(histogram);
		}

		int w = context.getWidth();
		int h = context.getHeight();
		int oneCount = 0;
		for (int x = 0; x < w; x++) {
			for (int y = 0; y < h; y++) {
				int p = context.getValue(x, y);
				if (p < divThreshold) {
					p = 1;
					oneCount++;
				} else {
					p = 0;
				}
				context.setValue(x, y, p);
			}
		}

		int total = w * h;
		if (oneCount > (total - oneCount)) {
			for (int x = 0; x < w; x++) {
				for (int y = 0; y < h; y++) {
					int p = context.getValue(x, y);
					context.setValue(x, y, 1 - p);
				}
			}
		}

		context.setBinary(true);

	}
}
